home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
VGX
/
shadows
/
shadows.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
25KB
|
918 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
shadows.c - Draw a scene with shadow-volume shadow calculation
using VGX graphics hardware stencil planes.
Tim Heidmann, Silicon Graphics
Created June 1, 1988
Last Edit November 25, 1991
*/
#include <stdio.h>
#include <gl.h>
#include <gl/image.h>
#include <device.h>
#include <math.h>
#include <string.h>
#include "trackball.h"
#include "shadows.h"
#include "glo_obj.h"
#include "vect.h"
#define PI (3.1415926535)
#define TWOPI (6.283185308)
#define RAD2DEG (180.0/PI)
#define MAXOBJS 10
#define MAXLITES 8
#define STENZERO 128
#define SPACING 1.2
#define SHADOWLENGTH 100.0
#define NEARCLIP 0.25
#define FARCLIP 30.0
#define WINHEIGHT 0.1
/* Scene description global variables */
float obj_posn[MAXOBJS][3];
float obj_scale[MAXOBJS];
Matrix obj_rotMatrix[MAXOBJS];
int obj_litMaterial[MAXOBJS];
int obj_shadowMaterial[MAXOBJS];
int obj_highMaterial[MAXOBJS];
int obj_texture[MAXOBJS];
glo_ObjPtr obj_drawlist[MAXOBJS];
PolyDataPtr obj_data[MAXOBJS];
int nObjects = 0;
float light_posn[MAXLITES][3];
float jitter_light_posn[MAXLITES][3];
float jitter_light_range[MAXLITES][3];
int nLights = 0;
/* Viewing, window, and interaction parameters */
float eyex[] = { 0.0, 0.0, 9.0};
float gazex[] = { 0.0, 0.0, 0.0};
Matrix scene_rotMatrix;
float scene_spin[4] = {0.0, 0.0, 0.0, 1.0};
float scene_posn[3] = {0.0, 0.0, 0.0};
int windowParmsSet;
float windowParms[6];
float viewWindow[3] = {WINHEIGHT, NEARCLIP, FARCLIP};
Screencoord lox,hix,loy,hiy;
int win_ox, win_oy, win_sx, win_sy;
float nmx, nmy, omx, omy;
Boolean acFlag = FALSE;
int acCount = -1;
int acFrames = 64;
/* Constants to support texture mapping - property arrays, texgen parameters */
float tev_val[] = {TV_NULL};
float tex_val[] =
{TX_MINFILTER, TX_BILINEAR, TX_MAGFILTER, TX_BILINEAR, TX_NULL};
float tex_sparams[] = {1.0, 0.0, 0.0, 0.0};
float tex_tparams[] = {0.0, 0.0, 1.0, 0.0};
float subdiv_params[] = {10000.0, 0.0, 0.0};
/* Program execution flags and modes */
char *sceneFileName;
char *imageFileName;
enum {showScene, showVolumes, showMask, showShadows} showMode=showScene;
int showVolSilEdges;
int showVolShadowEdges;
int showVolObjects;
long CmdMenu;
Boolean canZBuffer, canStencil, canAccum;
int stencilZero;
/* What colors to use for what stencil values in showMask display mode */
/* In/Out: 1/1 2/2 3/3 1/0 2/1 3/2 2/0, 0/0 is clear */
int maskValue[] = {0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x8};
int maskColor[] = {
0x00ff00ff, /* 1/1 - in == out, magenta */
0x00ff00ff, /* 2/2 */
0x00ff00ff, /* 3/3 */
0x00ff0000, /* 1/0 - in == out+1, blue */
0x00ff0000, /* 2/1 */
0x00ff0000, /* 3/2 */
0x00c0c000, /* 2/0 - in == out+2, blue-green */
};
int nMasks = (sizeof(maskValue)/sizeof(int));
Matrix IdentMat = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
/* Forward definitions */
void
ParseArgs(int c, char *v[]);
int
GetTBPosition(int state);
void
UpdateSceneRot();
void
AccumNext();
void
DoCmdMenu(Boolean *quitFlag, Boolean *redrawFlag);
void
GetNextSilEdge(EdgePtr edgeList, int thisEdge, int thisSide,
int *pNextEdge, int *pNextSide);
main(int argc, char *argv[])
{
/* These flags control the operation of the main loop:
done - When true, bust out of the loop and exit;
refresh - need to redraw the scene;
okayToBlock - nothing spinning, being moved, or accumulating -
can wait for event;
buttonState - combination of LEFT & MID mouse buttons -
!=0 means scene is being moved.
spinning - The last movement had some rotation, which continues
when the mouse button is released.
acFlag - We want to jitter lights and accumulate when scene not moving.
acCount - >0: more to accumulate, ==0: done, <0: clear and accumulate.
*/
Boolean done, refresh, okayToBlock, spinning;
short val, i, j;
int buttonState;
char buf[100];
ParseArgs(argc, argv);
InitGFX();
InitDevices();
InitMenus();
InitScene();
qenter(REDRAW,0);
buttonState = GetButtonState();
spinning = FALSE;
for (done = FALSE;;) {
/* Go get all the events or maybe sit and wait for one */
while(qtest() || okayToBlock) {
switch(qread(&val)) {
case REDRAW:
ShapeWindow(); refresh = TRUE; break;
case ESCKEY:
case QKEY:
case WINQUIT:
done = TRUE; break;
case LEFTMOUSE:
case MIDDLEMOUSE:
buttonState = GetButtonState(); break;
case RIGHTMOUSE:
if (val) DoCmdMenu(&done, &refresh); break;
default:
break;
}
okayToBlock = FALSE;
}
/* Now handle all the events */
if (done) break;
if (buttonState != 0) {
spinning = GetTBPosition(buttonState); refresh = TRUE;
}
if (spinning) {
UpdateSceneRot(); refresh = TRUE;
}
if (refresh) {
RepositionLights();
DrawFrame(); swapbuffers(); acCount = -1; refresh = FALSE;
} else if (acFlag && showMode == showShadows)
AccumNext();
okayToBlock = (buttonState != 0) ? FALSE :
spinning ? FALSE :
(showMode == showShadows && acFlag && acCount != 0) ? FALSE : TRUE;
if (okayToBlock && imageFileName != NULL) {
sprintf(buf, "scrsave %s %d %d %d %d", imageFileName,
lox, hix, loy, hiy);
system(buf);
break;
}
}
FinishDevices();
FinishGFX();
}
int
GetButtonState() {
omx = 2.0 * (getvaluator(MOUSEX) - win_ox) / win_sx - 1.0;
omy = 2.0 * (getvaluator(MOUSEY) - win_oy) / win_sy - 1.0;
return getbutton(LEFTMOUSE) << 1 | getbutton(MIDDLEMOUSE);
}
int
GetTBPosition(int state) {
float delta[3];
int spinning;
nmx = 2.0 * (getvaluator(MOUSEX) - win_ox) / win_sx - 1.0;
nmy = 2.0 * (getvaluator(MOUSEY) - win_oy) / win_sy - 1.0;
spinning = FALSE;
switch (state) {
case 1: /* Middle mouse - rotate */
trackball(scene_spin, omx, omy, nmx, nmy);
/* No spin is scene_spin == {0,0,0,1};
vlength looks at just 1st 3 elements */
spinning = vlength(scene_spin) > 0.00001;
break;
case 2: /* Left mouse - translate */
vset(delta, nmx - omx, nmy - omy, 0.0);
vadd(scene_posn, delta, scene_posn);
break;
case 3: /* Left & Middle - Track in/out */
scene_posn[2] += nmy - omy;
break;
default:
break;
}
omx = nmx;
omy = nmy;
return spinning;
}
void
UpdateSceneRot() {
Matrix spinMatrix;
build_rotmatrix(spinMatrix, scene_spin);
vmultmatrix(scene_rotMatrix, spinMatrix, scene_rotMatrix);
}
void
AccumNext() {
int nDone;
/* Reset accumulation buffer and count if necessary */
if (acCount == 0) return;
if (acCount < 0) {
acbuf(AC_CLEAR, 0.0);
acCount = acFrames;
}
/* Accumulate another frame */
JitterLights();
DrawFrame();
readsource(SRC_BACK);
acbuf(AC_ACCUMULATE, 1.0);
acCount--;
/* Copy accumulation buffer back to display whenever
- count reaches specified number (acFrames)
- count is a power of two, >=4 (4,8,16,32...) */
nDone = acFrames - acCount;
if (acCount == 0 || ((nDone&(nDone-1)) == 0 && nDone >= 4)) {
acbuf(AC_RETURN, 1.0/nDone);
swapbuffers();
}
}
void
ParseArgs(int c, char *v[]) {
char *callName;
int i, iLeft, iRight, iBottom, iTop;
sceneFileName = NULL;
imageFileName = NULL;
showMode = showScene;
showVolSilEdges = TRUE;
showVolShadowEdges = FALSE;
showVolObjects = TRUE;
windowParmsSet = FALSE;
callName = v[0];
for (c--, v++; c > 0; c--, v++) {
if (v[0][0] == '-')
switch (v[0][1]) {
case 'p': /* Window position */
iLeft = atoi(v[1]);
iRight = atoi(v[2]);
iBottom = atoi(v[3]);
iTop = atoi(v[4]);
prefposition(iLeft, iRight, iBottom, iTop);
c -= 4; v += 4;
break;
case 'w': /* Window perspective parameters */
for (i=0; i<6; i++)
if (sscanf(v[1 + i], "%f", windowParms + i) != 1)
BadCall(callName);
windowParmsSet = TRUE;
c -= 6; v += 6;
break;
case 'o': /* Save scene as .rgb file */
imageFileName = v[1];
v += 1; c -= 1;
break;
case 'j': /* Jitter frames */
acFlag = TRUE;
acFrames = atoi(v[1]);
v++; c--;
break;
case 'b': /* Block until this program finishes */
foreground(); break;
case 'n': /* Normal Scene */
showMode = showScene; break;
case 'v': /* Show volumes */
showMode = showVolumes; break;
case 'm': /* Show mask */
showMode = showMask; break;
case 's': /* Show shadows */
showMode = showShadows; break;
case 'e': /* Show silhouette edges */
showVolSilEdges = TRUE; break;
case 'f': /* Don't show silhouette edges */
showVolSilEdges = FALSE; break;
case 'E': /* Show shadow volume edges */
showVolShadowEdges = TRUE; break;
case 'F': /* Don't show shadow volume edges */
showVolShadowEdges = FALSE; break;
case 'd': /* Hide objects */
showVolObjects = FALSE; break;
default:
BadCall(callName);
break;
}
else
/* Parse the scene file name */
sceneFileName = v[0];
}
/* Check for valid operations */
canZBuffer = getgdesc(GD_BITS_NORM_ZBUFFER) > 0;
canStencil = getgdesc(GD_BITS_STENCIL) > 0;
canAccum = getgdesc(GD_BITS_ACBUF_HW) > 0;
if (acFlag && !canAccum) {
fprintf(stderr,
"This machine has no accumulation buffer, which is required\n");
fprintf(stderr,
"to compute soft shadows by jittering the light sources.\n");
acFlag = FALSE;
}
if (!canStencil) {
fprintf(stderr,
"This machine has no stencil planes, which are required for\n");
fprintf(stderr,
"shadow calculation.\n");
acFlag = FALSE;
}
if (!canZBuffer) {
fprintf(stderr,
"This program requires a z-buffer to run.\n");
exit(1);
}
}
BadCall(char *callName) {
fprintf(stderr, "usage: %s [options] [<scene filename>]\n", callName);
fprintf(stderr, " -p <left right bottom top> Window position\n");
fprintf(stderr, " -w <left right bottom top near far>\n");
fprintf(stderr, " Window parameters\n");
fprintf(stderr, " -o <filename> Output to .rgb file\n");
fprintf(stderr, " -j <frames> Max Jitter Frames\n");
fprintf(stderr, " -b Block until program finishes\n");
fprintf(stderr, " The following modes are exclusive:\n");
fprintf(stderr, " -n Show normal scene\n");
fprintf(stderr, " -v Show volumes\n");
fprintf(stderr, " -m Show mask\n");
fprintf(stderr, " -s Show shadows\n");
fprintf(stderr, " The following flags apply to volume mode only:\n");
fprintf(stderr, " -e Show silhouette edges\n");
fprintf(stderr, " -f Don't show silhouette edges\n");
fprintf(stderr, " -E Show shadow volume edges\n");
fprintf(stderr, " -F Don't show shadow volume edges\n");
fprintf(stderr, " -d Hide objects\n");
exit(1);
}
InitGFX()
{
#ifdef DEBUG
foreground();
#endif
winopen("Shadow Volumes");
RGBmode();
doublebuffer();
stensize(8);
acsize(16);
stencilZero = STENZERO;
gconfig();
cpack(0x00000000);
clear();
swapbuffers();
zbuffer(TRUE);
lsetdepth(0x000100, 0x7fffff);
subpixel(TRUE);
mmode(MVIEWING);
tevdef(1, 0, tev_val);
tevbind(TV_ENV0, 1);
texgen(TX_S, TG_LINEAR, tex_sparams);
texgen(TX_T, TG_LINEAR, tex_tparams);
texgen(TX_S, TG_ON, NULL);
texgen(TX_T, TG_ON, NULL);
}
FinishGFX() {
gexit();
}
InitDevices() {
if (imageFileName == NULL) {
/* If we are saving an image, don't allow interaction */
qdevice(LEFTMOUSE);
qdevice(MIDDLEMOUSE);
qdevice(RIGHTMOUSE);
}
qdevice(ESCKEY);
qdevice(QKEY);
}
FinishDevices() {
unqdevice(LEFTMOUSE);
unqdevice(MIDDLEMOUSE);
unqdevice(RIGHTMOUSE);
unqdevice(ESCKEY);
unqdevice(QKEY);
}
InitMenus() {
CmdMenu = defpup("");
MakeCmdMenu();
}
MakeCmdMenu() {
freepup(CmdMenu);
CmdMenu=defpup("Shadow Scene %t");
addtopup(CmdMenu, "Show Objects Only %x3");
addtopup(CmdMenu, "Show Volumes %x1");
if (canStencil) {
addtopup(CmdMenu, "Show Mask %x2");
addtopup(CmdMenu, "Show Shadows %x4 %l");
}
if (canAccum)
if (acFlag)
addtopup(CmdMenu, "Turn Soft Shadows Off %x5 %l");
else
addtopup(CmdMenu, "Turn Soft Shadows On %x5 %l");
addtopup(CmdMenu, "Quit %x0");
}
void
DoCmdMenu(Boolean *quitFlag, Boolean *redrawFlag)
{
*quitFlag = FALSE;
*redrawFlag = TRUE;
switch (dopup(CmdMenu)) {
case 0: *quitFlag = TRUE; break;
case 1: showMode=showVolumes; break;
case 2: showMode=showMask; break;
case 3: showMode=showScene; break;
case 4: showMode=showShadows; break;
case 5: acFlag = !acFlag; MakeCmdMenu(); break;
default: break;
}
}
ShapeWindow()
{
/* Reshape window, set up perspective and camera transform.
Provide an undistorted view given any window aspect ratio.
viewWindow[0]: height of near plane window,
viewWindow[1]: near clipping plane,
viewWindow[2]: far clipping plane */
long xorg, yorg;
float aspect;
reshapeviewport();
getviewport(&lox,&hix,&loy,&hiy);
getorigin(&win_ox, &win_oy);
lox += win_ox; hix += win_ox;
loy += win_oy; hiy += win_oy;
win_sx = hix - lox;
win_sy = hiy - loy;
aspect = ((float) win_sx)/win_sy;
mmode(MPROJECTION);
if (windowParmsSet)
window(windowParms[0], windowParms[1],
windowParms[2], windowParms[3],
windowParms[4], windowParms[5]);
else
if (aspect > 1.0)
window(-viewWindow[0]*aspect,viewWindow[0]*aspect,
-viewWindow[0],viewWindow[0],
viewWindow[1], viewWindow[2]);
else
window(-viewWindow[0],viewWindow[0],
-viewWindow[0]/aspect,viewWindow[0]/aspect,
viewWindow[1], viewWindow[2]);
lookat(eyex[0], eyex[1], eyex[2], gazex[0], gazex[1], gazex[2], 0);
mmode(MVIEWING);
loadmatrix(IdentMat);
}
DrawFrame() {
int i, j;
czclear(0x00000000,0x7fffff);
/* Draw the Scene */
zbuffer(TRUE);
zwritemask(0xffffffff);
wmpack(0xffffffff);
blendfunction(BF_ONE, BF_ZERO);
for (i=0; i<nLights; i++) lmbind(LIGHT0+i, i+1);
stencilZero = STENZERO;
switch (showMode) {
case showScene:
DrawObjects(obj_litMaterial);
return;
case showVolumes:
if (showVolObjects) DrawObjects(obj_litMaterial);
break;
case showMask:
stencilZero = 0;
DrawObjects(obj_litMaterial);
break;
case showShadows:
DrawObjects(obj_shadowMaterial);
break;
default: ;
}
/* Draw the shadow volumes */
lmbind(MATERIAL, 0);
zwritemask(0x00000000);
switch (showMode) {
case showVolumes:
/* To draw the volumes: */
wmpack(0xffffffff);
blendfunction(BF_SA, BF_MSA);
cpack(0x18ffffff);
DrawShadows(0);
/* Now the silhouette edges */
if (showVolSilEdges) {
cpack(0x0000ffff);
blendfunction(BF_ONE, BF_ZERO);
DrawSilEdges();
}
break;
case showMask:
/* Build the stencil shadow mattes: */
sclear(stencilZero);
wmpack(0x00000000);
DrawShadows(0);
/* Draw the mask */
wmpack(0xffffffff);
zbuffer(FALSE);
for (i=0; i<nMasks; i++) {
stencil(TRUE, maskValue[i], SF_EQUAL, 0xff,
ST_KEEP, ST_KEEP, ST_KEEP);
DrawSquare(maskColor[i]);
}
stencil(FALSE, 0, 0, 0, 0, 0, 0);
break;
case showShadows:
for (i=0; i<nLights; i++) {
/* Set the lights */
for (j=0; j<nLights; j++) lmbind(LIGHT0+j, (j==i) ? j+1 : 0);
/* Build the stencil shadow mattes: */
sclear(stencilZero);
wmpack(0x00000000);
DrawShadows(i);
/* Draw shadowed elements */
wmpack(0xffffffff);
stencil(TRUE, stencilZero, SF_EQUAL, 0xff,
ST_KEEP, ST_KEEP, ST_KEEP);
blendfunction(BF_ONE, BF_ONE);
DrawObjects(obj_highMaterial);
}
stencil(FALSE, 0, 0, 0, 0, 0, 0);
break;
}
}
DrawObjects(int objMaterial[])
{
/* Draw all objects in this scene */
int i;
pushmatrix();
translate(scene_posn[0], scene_posn[1], scene_posn[2]);
multmatrix(scene_rotMatrix);
for (i=0; i<nObjects; i++) {
pushmatrix();
translate(obj_posn[i][0], obj_posn[i][1], obj_posn[i][2]);
multmatrix(obj_rotMatrix[i]);
scale(obj_scale[i], obj_scale[i], obj_scale[i]);
lmbind(MATERIAL, objMaterial[i]);
if (obj_texture[i] > 0) {
texbind(TX_TEXTURE_0, obj_texture[i]);
scrsubdivide(SS_DEPTH, subdiv_params);
glo_DrawObj(obj_drawlist[i]);
texbind(TX_TEXTURE_0, 0);
scrsubdivide(SS_OFF, NULL);
} else
glo_DrawObj(obj_drawlist[i]);
popmatrix();
}
popmatrix();
}
DrawShadows(int lighti) {
float x, y, z;
int i;
Matrix myMatrix;
for (i=0; i<nObjects; i++) {
pushmatrix();
translate(scene_posn[0], scene_posn[1], scene_posn[2]);
multmatrix(scene_rotMatrix);
translate(obj_posn[i][0], obj_posn[i][1], obj_posn[i][2]);
multmatrix(obj_rotMatrix[i]);
scale(obj_scale[i], obj_scale[i], obj_scale[i]);
getmatrix(myMatrix);
popmatrix();
DrawSilhouettes(obj_drawlist[i], obj_data[i], myMatrix,
jitter_light_posn[lighti]);
}
}
DrawSquare(long color)
{
Matrix saveViewMatrix, saveProjMatrix;
getmatrix(saveViewMatrix);
mmode(MPROJECTION);
getmatrix(saveProjMatrix);
mmode(MVIEWING);
cpack(color);
ortho2(-1.0, 1.0, -1.0, 1.0);
rectf(-1.0, -1.0, 1.0, 1.0);
mmode(MPROJECTION);
loadmatrix(saveProjMatrix);
mmode(MVIEWING);
loadmatrix(saveViewMatrix);
}
DrawSilhouettes(myOP, myPDP, xformMatrix, lightx)
glo_ObjPtr myOP;
PolyDataPtr myPDP;
Matrix xformMatrix;
float lightx[];
{
int i, iEdge, thisEdge, firstEdge, thisSide, iFace;
Matrix rotOnlyMat;
float xformedNormal[3], lightToEye[3];
float lightToV1[3], lightToLastV1[3];
float shadowFaceNormal[3];
float worldV1[3], worldV2[3], lastV1[3], lastV2[3];
EdgePtr pEdge;
Boolean ingoing, lastIngoing, onceThrough;
/* Get a rotation-only version of modeling transform for transforming
normals */
vmatcopy(xformMatrix, rotOnlyMat);
for (i=0; i<3; i++) rotOnlyMat[3][i] = 0.0;
/* Mark each face for lightedness */
for (iFace = 0; iFace < myPDP->nFaces; iFace++) {
vtransform(myPDP->faces[iFace].n, rotOnlyMat, xformedNormal);
myPDP->faces[iFace].lit = vdot(xformedNormal, lightx) > 0.0;
}
/* Evaluate and clear per-edge flags */
for (iEdge = 0, pEdge = myPDP->edges; iEdge < myPDP->nEdges;
iEdge++, pEdge++) {
pEdge->silhouetteFlag =
(pEdge->e[1].face < 0 ||
myPDP->faces[pEdge->e[0].face].lit !=
myPDP->faces[pEdge->e[1].face].lit);
pEdge->markedFlag = FALSE;
}
/* For each silhouette edge, if it has not been projected yet,
trace a complete loop of silhouette edges, projecting shadow volumes */
/* iEdge is main edge list index; thisEdge, firstEdge, and pEdge trace
silhouette loops */
vsub(eyex, lightx, lightToEye);
for (iEdge = 0; iEdge<myPDP->nEdges; iEdge++) {
/* If this is not a silhouette edge, or if we've projected it, skip */
pEdge = myPDP->edges + iEdge;
if (!pEdge->silhouetteFlag || pEdge->markedFlag) continue;
firstEdge = thisEdge = iEdge;
thisSide = 0;
onceThrough = FALSE;
lastIngoing = -1;
if (showMode == showShadows) bgnqstrip();
for (;;) {
/* Transform first edge vertex to world coordinates */
vtransform(myOP->t[pEdge->e[thisSide].vertex],
xformMatrix, worldV1);
/* Project first edge vertex away from light to get a new vertex. */
vsub(worldV1, lightx, lightToV1);
vscale(lightToV1, SHADOWLENGTH/vlength(lightToV1));
vadd(worldV1, lightToV1, worldV2);
if (onceThrough) {
/* Is this shadow face going into or out of shadow? */
vcross(lightToLastV1, lightToV1, shadowFaceNormal);
ingoing = vdot(shadowFaceNormal, lightToEye) > 0;
if (!myPDP->faces[pEdge->e[thisSide].face].lit)
ingoing = !ingoing;
}
/* Set up and draw next 2 vertices of this shadow face quad */
if (onceThrough)
if (showMode == showShadows) {
if (lastIngoing != ingoing) {
endqstrip();
stencil(TRUE, 0, SF_ALWAYS, 0xff, ST_KEEP, ST_KEEP,
ingoing?ST_INCR:ST_DECR);
bgnqstrip();
v3f(lastV1); v3f(lastV2);
lastIngoing = ingoing;
}
v3f(worldV1); v3f(worldV2);
}
else if (showMode == showMask) {
for (i=0; i<(ingoing?4:1); i++) {
stencil(TRUE, 0, SF_ALWAYS, 0xff, ST_KEEP, ST_KEEP,
ST_INCR);
bgnpolygon();
v3f(lastV1); v3f(lastV2); v3f(worldV2); v3f(worldV1);
endpolygon();
}
}
else if (showMode == showVolumes) {
bgnpolygon();
v3f(lastV1); v3f(lastV2); v3f(worldV2); v3f(worldV1);
endpolygon();
if (showVolShadowEdges) {
/* Draw the edges of the shadow faces for clarity */
bgnclosedline();
v3f(lastV1); v3f(lastV2); v3f(worldV2); v3f(worldV1);
endclosedline();
}
}
/* Exit if we've completed a full loop of sihouettes */
if (thisEdge == firstEdge && onceThrough) break;
/* Update loop indices, pointers, and values */
pEdge->markedFlag = TRUE;
vcopy(lightToV1, lightToLastV1);
vcopy(worldV1, lastV1);
vcopy(worldV2, lastV2);
GetNextSilEdge(myPDP->edges, thisEdge, thisSide,
&thisEdge, &thisSide);
pEdge = myPDP->edges + thisEdge;
onceThrough = TRUE;
}
if (showMode == showShadows) endqstrip();
}
}
void
GetNextSilEdge(EdgePtr edgeList, int thisEdge, int thisSide,
int *pNextEdge, int *pNextSide) {
int nextEdge, nextSide;
for (;;) {
nextEdge = edgeList[thisEdge].e[thisSide].nextEdge;
nextSide = edgeList[thisEdge].e[thisSide].nextSide;
/* If the next edge around this polygon is a silhouette, we're done */
if (edgeList[nextEdge].silhouetteFlag) break;
/* Otherwise, go to the next polygon and check the next edge. */
thisEdge = nextEdge;
thisSide = 1 - nextSide;
}
*pNextEdge = nextEdge;
*pNextSide = nextSide;
}
DrawSilEdges() {
/* For each object, transform and draw all silhouette edges, based
on lit flags set by DrawSilhouettes. Yellow solid lines for
visible edges, dotted lines for those that fail z-buffer test.
Fudge the lsetdepth to help keep visible lines from breaking up. */
int iObj, iEdge;
EdgePtr thisEdge;
lsetdepth(0x000000, 0x7ffeff);
deflinestyle(1, 0xf0f0);
for (iObj=0; iObj<nObjects; iObj++) {
pushmatrix();
translate(scene_posn[0], scene_posn[1], scene_posn[2]);
multmatrix(scene_rotMatrix);
translate(obj_posn[iObj][0], obj_posn[iObj][1], obj_posn[iObj][2]);
multmatrix(obj_rotMatrix[iObj]);
scale(obj_scale[iObj], obj_scale[iObj], obj_scale[iObj]);
for (iEdge = 0, thisEdge = obj_data[iObj]->edges;
iEdge<obj_data[iObj]->nEdges; iEdge++, thisEdge++) {
/* If this is a silhouette edge, draw it. */
if (thisEdge->silhouetteFlag) {
/* Draw hidden, dashed lines first */
setlinestyle(1);
zfunction(ZF_GREATER);
bgnline();
v3f(obj_drawlist[iObj]->t[thisEdge->e[0].vertex]);
v3f(obj_drawlist[iObj]->t[thisEdge->e[1].vertex]);
endline();
/* Then visible, solid lines next */
setlinestyle(0);
zfunction(ZF_LEQUAL);
bgnline();
v3f(obj_drawlist[iObj]->t[thisEdge->e[0].vertex]);
v3f(obj_drawlist[iObj]->t[thisEdge->e[1].vertex]);
endline();
}
}
popmatrix();
}
lsetdepth(0x000100, 0x7fffff);
}
int
JitterLights() {
int i, j;
for (i=0; i<nLights; i++)
for (j=0; j<3; j++)
jitter_light_posn[i][j] = light_posn[i][j] +
((random() & 0xffff)/32768.0 - 1.0) *
jitter_light_range[i][j];
}
int
RepositionLights() {
int i, j;
for (i=0; i<nLights; i++)
for (j=0; j<3; j++)
jitter_light_posn[i][j] = light_posn[i][j];
}